﻿using System.Security.Claims;
using AutoMapper;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Zhaoxi.IdentitySample.EmailService;
using Zhaoxi.IdentitySample.Web.Entites;
using Zhaoxi.IdentitySample.Web.Models;

namespace Zhaoxi.IdentitySample.Web.Controllers
{
    public class AccountController : Controller
    {
        private readonly IMapper _mapper;
        private readonly UserManager<User> _userManager;

        public AccountController(IMapper mapper, UserManager<User> userManager)
        {
            _mapper = mapper;
            _userManager = userManager;
        }

        [HttpGet]
        public IActionResult Register()
        {
            return View();
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Register([FromServices]IEmailSender emailSender, UserRegistrationModel userModel)
        {
            if(!ModelState.IsValid)
            {
                return View(userModel);
            }

            var user = _mapper.Map<User>(userModel);

            var result = await _userManager.CreateAsync(user, userModel.Password);
            if(!result.Succeeded)
            {
                foreach (var error in result.Errors)
                {
                    ModelState.TryAddModelError(error.Code, error.Description);
                }

                return View(userModel);
            }

            var token = await _userManager.GenerateEmailConfirmationTokenAsync(user);
            var confirmationLink = Url.Action(nameof(ConfirmEmail), "Account", new { token, email = user.Email }, Request.Scheme);
            var message = new Message( $"{user.LastName}",user.Email, "请确认电子邮件", confirmationLink);
            await emailSender.SendEmailAsync(message);

            await _userManager.AddToRoleAsync(user, "Guest");

            await _userManager.SetTwoFactorEnabledAsync(user, true);

            // await _userManager.GetTwoFactorEnabledAsync(user);

            return RedirectToAction(nameof(HomeController.Index), "Home");
        }

        [HttpGet]
        public async Task<IActionResult> ConfirmEmail(string token, string email)
        {
            var user = await _userManager.FindByEmailAsync(email);
            if (user == null)
                return View("Error");
            var result = await _userManager.ConfirmEmailAsync(user, token);
            return View(result.Succeeded ? nameof(ConfirmEmail) : "Error");
        }

        [HttpGet]
        public IActionResult Login(string returnUrl = null)
        {
            ViewData["ReturnUrl"] = returnUrl;
            return View();
        }

        // [HttpPost]
        // [ValidateAntiForgeryToken]
        // public async Task<IActionResult> Login(UserLoginModel userModel, string returnUrl = null)
        // {
        //     if(!ModelState.IsValid)
        //     {
        //         return View(userModel);
        //     }
        //
        //     var user = await _userManager.FindByEmailAsync(userModel.Email);
        //     if(user != null && 
        //        await _userManager.CheckPasswordAsync(user, userModel.Password) &&
        //        await _userManager.IsEmailConfirmedAsync(user))
        //     {
        //         var identity = new ClaimsIdentity(IdentityConstants.ApplicationScheme);
        //         identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id));
        //         identity.AddClaim(new Claim(ClaimTypes.Name, user.UserName));
        //         // 可以添加更多自定义用户信息
        //         identity.AddClaim(new Claim("firstname", user.FirstName));
        //         identity.AddClaim(new Claim("lastname", user.LastName));
        //         var roles = await _userManager.GetRolesAsync(user);
        //         foreach (var role in roles)
        //         {
        //             identity.AddClaim(new Claim(ClaimTypes.Role, role));
        //         }
        //
        //         await HttpContext.SignInAsync(IdentityConstants.ApplicationScheme,
        //             new ClaimsPrincipal(identity));
        //
        //         return RedirectToLocal(returnUrl);
        //     }
        //
        //     ModelState.AddModelError("", "无效的用户名或密码");
        //     return View();
        // }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Login([FromServices]IEmailSender emailSender, [FromServices]SignInManager<User> signInManager, UserLoginModel userModel, string returnUrl = null)
        {
            if(!ModelState.IsValid)
            {
                return View(userModel);
            }

            var result = await signInManager.PasswordSignInAsync(
                userModel.Email, userModel.Password, 
                userModel.RememberMe, true);

            if (result.IsLockedOut)
            {
                var forgotPassLink = Url.Action(nameof(ForgotPassword),"Account", new { }, Request.Scheme);
                var content = $"您的帐户已锁定，要重置密码，请单击此链接: {forgotPassLink}";
                var message = new Message(userModel.Email,userModel.Email, "您的账户由于多次登录失败被锁定！", content);
                await emailSender.SendEmailAsync(message);
                ModelState.AddModelError("", "账户被锁定");
                return View();
            }
            
            if(result.RequiresTwoFactor)
            {
                return RedirectToAction(nameof(LoginTwoStep), new { userModel.Email, userModel.RememberMe, returnUrl});
            }

            if (result.Succeeded)
            {
                return RedirectToLocal(returnUrl);
            }

            ModelState.AddModelError("", "无效的用户名或密码");
            return View();
        }

        [HttpGet]
        public async Task<IActionResult> LoginTwoStep([FromServices]IEmailSender emailSender, string email, bool rememberMe, string returnUrl = null)
        {
            var user = await _userManager.FindByEmailAsync(email);
            if (user == null)
            {
                return View("Error");
            }

            var providers = await _userManager.GetValidTwoFactorProvidersAsync(user);
            if (!providers.Contains("Email"))
            {
                return View("Error");
            }

            var token = await _userManager.GenerateTwoFactorTokenAsync(user, "Email");

            var message = new Message( user.LastName, email, "验证码", token);
            await emailSender.SendEmailAsync(message);

            ViewData["ReturnUrl"] = returnUrl;
            return View();
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> LoginTwoStep([FromServices]SignInManager<User> signInManager, TwoStepModel twoStepModel, string returnUrl = null)
        {
            if (!ModelState.IsValid)
            {
                return View(twoStepModel);
            }

            var user = await signInManager.GetTwoFactorAuthenticationUserAsync();
            if(user == null)
            {
                return View("Error");
            }

            var result = await signInManager.TwoFactorSignInAsync("Email", twoStepModel.TwoFactorCode, twoStepModel.RememberMe, rememberClient: false);
            if(result.Succeeded)
            {
                return RedirectToLocal(returnUrl);
            }

            if(result.IsLockedOut)
            {
                ModelState.AddModelError("", "该帐户已被锁定");
                return View();
            }

            ModelState.AddModelError("", "无效的登录尝试");
            return View();
        }

        private IActionResult RedirectToLocal(string returnUrl)
        {
            if (Url.IsLocalUrl(returnUrl))
                return Redirect(returnUrl);
            else
                return RedirectToAction(nameof(HomeController.Index), "Home");

        }

        public async Task<IActionResult> Logout([FromServices]SignInManager<User> signInManager)
        {
            await signInManager.SignOutAsync();

            return RedirectToAction(nameof(HomeController.Index), "Home");
        }


        [HttpGet]
        public IActionResult ForgotPassword()
        {
            return View();
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> ForgotPassword([FromServices]IEmailSender emailSender, ForgotPasswordModel forgotPasswordModel)
        {
            if (!ModelState.IsValid)
                return View(forgotPasswordModel);

            var user = await _userManager.FindByEmailAsync(forgotPasswordModel.Email);
            if (user == null)
                return RedirectToAction(nameof(ForgotPasswordConfirmation));

            var token = await _userManager.GeneratePasswordResetTokenAsync(user);
            var callback = Url.Action(nameof(ResetPassword), "Account", new { token, email = user.Email }, Request.Scheme);

            var message = new Message($"{user.FirstName}{user.LastName}", user.Email, "重置密码", callback);
            await emailSender.SendEmailAsync(message);

            return RedirectToAction(nameof(ForgotPasswordConfirmation));
        }

        public IActionResult ForgotPasswordConfirmation()
        {
            return View();
        }

        [HttpGet]
        public IActionResult ResetPassword(string token, string email)
        {
            var model = new ResetPasswordModel { Token = token, Email = email };
            return View(model);
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> ResetPassword(ResetPasswordModel resetPasswordModel)
        {
            if (!ModelState.IsValid)
                return View(resetPasswordModel);

            var user = await _userManager.FindByEmailAsync(resetPasswordModel.Email);

            if (user == null)
                RedirectToAction(nameof(ResetPasswordConfirmation));

            var resetPassResult = await _userManager.ResetPasswordAsync(user, resetPasswordModel.Token, resetPasswordModel.Password);

            if (resetPassResult.Succeeded) return RedirectToAction(nameof(ResetPasswordConfirmation));
            foreach (var error in resetPassResult.Errors)
            {
                ModelState.TryAddModelError(error.Code, error.Description);
            }
            return View();
        }

        [HttpGet]
        public IActionResult ResetPasswordConfirmation()
        {
            return View();
        }
    }
}
